/*
 Trabajo Practico 3 Ejercicio 2
 * Servidor
 Entrega número: 1

 - Integrantes:
		- Barrera, Lourdes				DNI: 33306634
		- Martinez, Guillermo			DNI: 34510461
		- Reyes, Leandro				DNI: 34213699
		- Rodriguez, Lucas				DNI: 34265017
*/

#include "defines.h"

// Variables Semáforo
sem_t* mutex_atencion;			// Server puede procesar
sem_t* mutex_mensaje;			// Hay mensaje para procesar
sem_t* mutex_mem;				// Mutex memoria compartida
sem_t* mutex_respuesta;			// Cliente puede leer respuesta
sem_t* mutex_inicio;			// Cliente puede iniciar

// Memoria compartida
char *mcompartida = NULL;

// Funciones
void crear_semaforos();
void cerrar_semaforos();
int posicion(int);

int sucursales[5] = {0,0,0,0,0};

int main()
{
	key_t sh_key;
	int id_mem = 0,flag=0,cant=0,i;
	int moneda=0,cotizacion=0,cant_comprada=0,pos=-1;
	pid_t sucursal;
	char recibir[BUFFER];
	total_mon_todas_suc por_moneda[CANT_MONEDAS];
	
	// Generar clave
	sh_key = ftok("/bin/ls",10);
	
	if(sh_key == -1)
		error("No consigo clave para memoria compartida\n");

	// Generar memoria compartida
	id_mem = shmget(sh_key,sizeof(char *),0777 | IPC_CREAT);
	if (id_mem == -1)
		error("No consigo Id para memoria compartida\n");
	
	// Generar semáforos
	crear_semaforos();
		
	// Attach memoria
	mcompartida = (char *)shmat(id_mem,NULL,0);
	if(mcompartida == NULL)
		error("No hay memoria compartida disponible\n");

	// Inicializar
	for(cant=0;cant<CANT_MONEDAS;cant++)
		for(i=0;i<5;i++)
		{
			por_moneda[cant][i].sucursal = 0;
			por_moneda[cant][i].total_pesos = 0;
			por_moneda[cant][i].ult_cotiz = 0;
			por_moneda[cant][i].prom_cotiz = 0;
			por_moneda[cant][i].total = 0;
			por_moneda[cant][i].cant_op = 0;
		}

	// Conexión de 5 clientes
	for(cant=0;cant<5;cant++)
	{
		V(mutex_inicio);
		P(mutex_mensaje);
		
		P(mutex_mem);
		strcpy(recibir,mcompartida);
		V(mutex_mem);
		
		// Guardo PID
		sucursales[cant]=atoi(recibir);
	}

	// Activar atención para recibir solicitudes
	V(mutex_atencion);

	do
	{
		printf("Esperando solicitud... ");
		
		// Esperar a que llegue mensaje
		P(mutex_mensaje);
		
		// Leer mensaje
		P(mutex_mem);
		strcpy(recibir,mcompartida);
		V(mutex_mem);
		
		///// Procesar información /////
		if(strcmp("FIN",recibir) != 0)
		{
			sscanf(recibir,"%d:%d:%d:%d\n",&moneda,&cotizacion,&cant_comprada,&sucursal);
			sprintf(recibir,"%d.",cotizacion*cant_comprada);
			
			pos = posicion(sucursal);
			por_moneda[moneda][pos].sucursal = sucursal;
			por_moneda[moneda][pos].total += cant_comprada;
			por_moneda[moneda][pos].cant_op++;
			por_moneda[moneda][pos].ult_cotiz = cotizacion;
			por_moneda[moneda][pos].total_pesos += cotizacion*cant_comprada;
			por_moneda[moneda][pos].prom_cotiz += cotizacion;
			
			// Escribir respuesta
			P(mutex_mem);
			strcpy(mcompartida,recibir);
			V(mutex_mem);
			
			// Habilito a cliente a leer
			V(mutex_respuesta);
			printf("Solicitud sucursal %d procesada\n",sucursal);
		}
		else
			flag=1;
	}while(flag == 0);

	// Impresión de resultados
	cant=0;
	printf("--- Resultados ---\n");
	for(cant=1;cant<CANT_MONEDAS;cant++)
	{
		flag=0;
		printf("> Moneda %d:\n",cant);
		for(i=0;i<5;i++)
			if(por_moneda[cant][i].sucursal != 0)	// La sucursal realizó operaciones
			{
				printf("\tSucursal %d/%d\n",por_moneda[cant][i].sucursal,i);
				printf("\t  Total:                %6d\n",por_moneda[cant][i].total);
				printf("\t  Cantidad operaciones: %6d\n",por_moneda[cant][i].cant_op);
				printf("\t  Cotización promedio:  %4.2f\n",(por_moneda[cant][i].prom_cotiz/(por_moneda[cant][i].cant_op)));
				printf("\t  Última cotización:    %6d\n",por_moneda[cant][i].ult_cotiz);
				printf("\t  Total en pesos:       $%5d\n\n",por_moneda[cant][i].total_pesos);
				flag=1;
			}
		if(!flag)
			printf("No hubo operaciones con esta moneda\n\n");
	}
	
	// Envio señal de finalización a clientes
	for(cant=0;cant<5;cant++)
		kill(sucursales[cant],SIGINT);

	// Liberar memoria
	shmdt(mcompartida);
	shmctl(id_mem, IPC_RMID,(struct shmid_ds *)NULL);
	cerrar_semaforos();
	return 0;
}

void crear_semaforos()
{
	if((mutex_atencion = sem_open(atencion, O_CREAT | O_EXCL ,0666, 0)) == SEM_FAILED)
		error("No se puede abrir el semáforo\n");
	
	if((mutex_mensaje =	sem_open(mensaje, O_CREAT | O_EXCL ,0666, 0)) == SEM_FAILED)
		error("No se puede abrir el semáforo\n");
	
	if((mutex_mem = sem_open(memoria, O_CREAT | O_EXCL ,0666, 1)) == SEM_FAILED)
		error("No se puede abrir el semáforo\n");
	
	if((mutex_respuesta = sem_open(respues, O_CREAT | O_EXCL ,0666, 0)) == SEM_FAILED)
		error("No se puede abrir el semáforo\n");
		
	if((mutex_inicio = sem_open(inicio, O_CREAT | O_EXCL ,0666, 0)) == SEM_FAILED)
		error("No se puede abrir el semáforo\n");
}

void cerrar_semaforos()
{
	if(mutex_atencion)
	{
		sem_close(mutex_atencion);
		sem_unlink(atencion);
	}
	if(mutex_mensaje)
	{
		sem_close(mutex_mensaje);
		sem_unlink(mensaje);
	}
	if(mutex_mem)
	{
		sem_close(mutex_mem);
		sem_unlink(memoria);
	}
	if(mutex_respuesta)
	{
		sem_close(mutex_respuesta);
		sem_unlink(respues);
	}
	if(mutex_inicio)
	{
		sem_close(mutex_inicio);
		sem_unlink(inicio);
	}
}

int posicion(int suc)
{
	int flag=1,pos=0;
	
	while(flag)
	{
		if(sucursales[pos] == 0)
		{
			sucursales[pos] = suc;			// Guardo PID de proceso
			return pos;						// Retorno posición en vector
		}
		
		else
			if(sucursales[pos] == suc)
				return pos;					// Retorno posición en vector
			else
				pos++;
	}
}
